package git

import (
	"fmt"
	"gopatch/global"
	"gopatch/utils/cmd"
	"regexp"
	"strings"
	"time"
)

// GitVersionStruct Git 提交记录结构体
type GitVersionStruct struct {
	GitVersion    string   `name:"修订号"`
	commitMessage string   `name:"提交信息"`
	commitTime    string   `name:"提交时间"`
	updateFiles   []string `name:"更新/新增的文件(不带仓库路径)"`
	deleteFiles   []string `name:"删除的文件(不带仓库路径)"`
}

func (g *GitVersionStruct) IsZero() bool {
	return g.GitVersion == ""
}

// GetCommitMessage 获取提交信息
func (g *GitVersionStruct) GetCommitMessage() string {
	return g.commitMessage
}

// GetCommitTime 获取提交时间
func (g *GitVersionStruct) GetCommitTime(pattern string) string {
	// 解析时间字符串 2006-01-02 15:04:05 -0700
	timeT, err := time.Parse("2006-01-02 15:04:05 -0700", g.commitTime)
	if err != nil {
		panic(fmt.Errorf("解析提交时间报错,%v\n", err))
	}

	// 将时间格式化为指定格式
	return timeT.Format(pattern)
}

// 添加需要更新的文件
func (g *GitVersionStruct) putUpdateFile(updateFile string) {

	// 如果存在不纳入补丁管理的文件，就在这里检查
	neverPatchFiles := global.GetNeverPatchFiles()
	if neverPatchFiles != nil && len(neverPatchFiles) > 0 {
		for _, npFile := range neverPatchFiles {
			// 将分隔符全部置为 /
			npFile = strings.ReplaceAll(npFile, "\\", "/")
			if strings.Contains(updateFile, npFile) {
				global.AppendMsg(global.ERROR, fmt.Sprintf("文件 %s 不纳入补丁\n", updateFile))
				return
			}
		}
	}

	g.updateFiles = append(g.updateFiles, updateFile)
}

func (g *GitVersionStruct) GetUpdateFiles() []string {
	return g.updateFiles
}

// 添加需要删除的文件
func (g *GitVersionStruct) putDeleteFile(deleteFile string) {
	g.deleteFiles = append(g.deleteFiles, deleteFile)
}

func (g *GitVersionStruct) GetDeleteFiles() []string {
	return g.deleteFiles
}

// HandleGitVersion 根据修订号处理数据，获取更新、新增、删除的文件
func (g *GitVersionStruct) HandleGitVersion() error {
	if g == nil || len(g.GitVersion) <= 0 || len(strings.ReplaceAll(g.GitVersion, " ", "")) <= 0 {
		return fmt.Errorf("处理Git修订号异常,修订号不能为空")
	}

	// 使用正则表达式匹配行结束符
	re := regexp.MustCompile(`\r?\n`)

	// 提取提交记录备注信息
	commitMsgOutput, err := cmd.ExecuCmdWithTargetDir(global.GetProperty().BaseProjectPath,
		"git", "show", g.GitVersion, "--pretty=format:%B",
	)

	if err != nil {
		return fmt.Errorf("version:[%s]获取提交记录备注信息报错,%v", g.GitVersion, err)
	}

	commitMsg := re.Split(commitMsgOutput.String(), 2)[0]
	g.commitMessage = commitMsg

	// 提取提交记录时间
	commitDateOutput, err := cmd.ExecuCmdWithTargetDir(
		global.GetProperty().BaseProjectPath,
		"git", "show", g.GitVersion, "--pretty=format:%ad", "--date=iso",
	)

	if err != nil {
		return fmt.Errorf("version:[%s]获取提交记录时间报错,%v", g.GitVersion, err)
	}

	commitDate := re.Split(commitDateOutput.String(), 2)[0]
	g.commitTime = commitDate

	// 处理提交记录中的文件信息
	output, err := cmd.ExecuCmdWithTargetDir(
		global.GetProperty().BaseProjectPath,
		"git", "show", "--name-status", g.GitVersion,
	)

	if err != nil {
		return fmt.Errorf("version:[%s]获取提交记录中的文件信息报错,%v", g.GitVersion, err)
	}

	commitLogStr := output.String()

	lines := re.Split(commitLogStr, -1)

	// 文件信息的起始行数
	startLine := 5
	for idx, line := range lines {
		if idx >= 5 {
			break
		}
		if len(line) == 0 {
			continue
		}
		// 前5行存在 Merge 行，则下面从第 6 行开始
		if line[:5] == "Merge" {
			startLine = 6
			break
		}
	}

	for idx, line := range lines {
		if idx < startLine {
			continue
		}
		handleFileLog(line, g)
	}

	return nil
}

func handleFileLog(fileLog string, gitVersion *GitVersionStruct) {
	fileLog = strings.TrimSpace(fileLog)
	if len(fileLog) == 0 {
		return
	}

	re := regexp.MustCompile(`\s+`)
	splits := re.Split(fileLog, -1)
	// log.Printf("---> %v\n", splits)

	mode := string(fileLog[0])
	switch mode {
	case "M":
		// 发生修改的文件
		gitVersion.putUpdateFile(splits[1])
	case "A":
		// 发生新增的文件
		gitVersion.putUpdateFile(splits[1])
	case "R":
		// 发生重命名的文件
		// 第一个是删除的文件
		gitVersion.putDeleteFile(splits[1])
		// 第二个是新增的文件
		gitVersion.putUpdateFile(splits[2])
	case "D":
		// 发生删除的文件
		gitVersion.putDeleteFile(splits[1])
	default:
		global.AppendMsg(
			global.ERROR,
			fmt.Sprintf("version:[%s]出现了未处理的 Git 操作类型 %s 请留意\n", gitVersion.GitVersion, fileLog),
		)
	}

}
